import socket
import threading
import json
import base64
import logging
import time
from PIL import Image
import io
from datetime import datetime
import struct
import os
import select
import platform
import subprocess
import asyncio
import websockets

# 配置日志
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

def get_all_applications():
    """获取电脑中用户应用程序及其exe路径（控制面板版本）"""
    applications = []
    
    if os.name == 'nt':  # Windows系统
        try:
            print("开始获取用户应用程序列表...")
            
            # 方法1: 使用PowerShell获取控制面板中的已安装程序（最准确）
            print("正在获取控制面板中的已安装程序...")
            try:
                import subprocess
                
                # 使用PowerShell命令获取已安装的程序
                ps_command = """
                Get-ItemProperty HKLM:\\Software\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\* | 
                Where-Object {$_.DisplayName -ne $null} | 
                Select-Object DisplayName, InstallLocation, DisplayVersion, Publisher | 
                Sort-Object DisplayName | 
                ConvertTo-Json -Compress
                """
                
                # 执行PowerShell命令（隐藏窗口）
                if platform.system() == "Windows":
                    result = subprocess.run(
                        ['powershell', '-WindowStyle', 'Hidden', '-Command', ps_command], 
                        capture_output=True, 
                        text=True, 
                        timeout=30,
                        creationflags=subprocess.CREATE_NO_WINDOW
                    )
                else:
                    result = subprocess.run(
                        ['powershell', '-Command', ps_command], 
                        capture_output=True, 
                        text=True, 
                        timeout=30
                    )
                
                if result.returncode == 0 and result.stdout.strip():
                    try:
                        import json
                        programs = json.loads(result.stdout)
                        
                        # 如果只有一个程序，转换为列表
                        if not isinstance(programs, list):
                            programs = [programs]
                        
                        print(f"  从PowerShell获取到 {len(programs)} 个程序")
                        
                        for program in programs:
                            display_name = program.get('DisplayName', '')
                            install_location = program.get('InstallLocation', '')
                            version = program.get('DisplayVersion', '')
                            publisher = program.get('Publisher', '')
                            
                            if display_name and install_location:
                                # 跳过系统程序
                                if not any(skip in display_name.lower() for skip in [
                                    'windows', 'microsoft', 'update', 'hotfix', 'security', 'kb'
                                ]):
                                    # 查找exe文件
                                    exe_path = None
                                    if os.path.exists(install_location):
                                        for root, dirs, files in os.walk(install_location):
                                            # 限制搜索深度
                                            if root.count(os.sep) - install_location.count(os.sep) > 2:
                                                continue
                                            
                                            for file in files:
                                                if file.lower().endswith('.exe'):
                                                    potential_exe = os.path.join(root, file)
                                                    if os.path.exists(potential_exe):
                                                        # 跳过系统文件
                                                        if not any(skip in potential_exe.lower() for skip in [
                                                            'windows', 'system32', 'syswow64', 'microsoft'
                                                        ]):
                                                            exe_path = potential_exe
                                                            break
                                            if exe_path:
                                                break
                                    
                                    if exe_path:
                                        applications.append({
                                            'name': display_name,
                                            'exe_path': exe_path,
                                            'filename': os.path.basename(exe_path),
                                            'version': version,
                                            'publisher': publisher,
                                            'install_location': install_location
                                        })
                                        print(f"  ✓ 找到应用: {display_name}")
                    
                    except json.JSONDecodeError as e:
                        print(f"  ⚠ JSON解析失败: {e}")
                        print(f"  PowerShell输出: {result.stdout[:200]}...")
                    except Exception as e:
                        print(f"  ⚠ 处理PowerShell结果失败: {e}")
                else:
                    print(f"  ⚠ PowerShell命令执行失败: {result.stderr}")
                    
            except subprocess.TimeoutExpired:
                print("  ⚠ PowerShell命令执行超时")
            except Exception as e:
                print(f"  ⚠ PowerShell执行失败: {e}")
            
            # 方法2: 从注册表获取App Paths（作为补充）
            print("正在扫描注册表App Paths...")
            try:
                import winreg
                
                registry_paths = [
                    r"SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths",
                    r"SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\App Paths"
                ]
                
                for base_path in registry_paths:
                    try:
                        with winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, base_path) as key:
                            subkey_count = winreg.QueryInfoKey(key)[0]
                            print(f"  注册表路径: {base_path}, 子键数量: {subkey_count}")
                            
                            # 限制扫描数量
                            max_keys = min(subkey_count, 30)
                            for i in range(max_keys):
                                try:
                                    subkey_name = winreg.EnumKey(key, i)
                                    with winreg.OpenKey(key, subkey_name) as subkey:
                                        try:
                                            # 获取默认值（通常是exe路径）
                                            default_value = winreg.QueryValue(key, subkey_name)
                                            if default_value and default_value.lower().endswith('.exe') and os.path.exists(default_value):
                                                # 跳过系统应用程序
                                                if not any(skip in default_value.lower() for skip in [
                                                    'windows', 'system32', 'syswow64', 'microsoft'
                                                ]):
                                                    app_name = os.path.splitext(subkey_name)[0]
                                                    applications.append({
                                                        'name': app_name,
                                                        'exe_path': default_value,
                                                        'filename': os.path.basename(default_value),
                                                        'version': '',
                                                        'publisher': '',
                                                        'install_location': os.path.dirname(default_value)
                                                    })
                                                    print(f"  ✓ 找到注册表应用: {app_name}")
                                        except (FileNotFoundError, OSError):
                                            continue
                                except (FileNotFoundError, OSError):
                                    continue
                    except (FileNotFoundError, OSError) as e:
                        print(f"  ⚠ 注册表路径访问失败: {base_path}, 错误: {e}")
                        continue
            except Exception as e:
                print(f"  ⚠ 注册表扫描失败: {e}")
            
            # 去重并排序
            print("正在去重和排序...")
            seen_paths = set()
            unique_apps = []
            for app in applications:
                if app['exe_path'] not in seen_paths:
                    seen_paths.add(app['exe_path'])
                    unique_apps.append(app)
            
            # 按名称排序
            unique_apps.sort(key=lambda x: x['name'].lower())
            
            print(f"✓ 扫描完成，找到 {len(unique_apps)} 个用户应用程序")
            
            # 显示前10个应用作为示例
            if unique_apps:
                print("\n前10个应用程序:")
                for i, app in enumerate(unique_apps[:10], 1):
                    print(f"  {i:2d}. {app['name']}")
                    if app.get('version'):
                        print(f"      版本: {app['version']}")
                    if app.get('publisher'):
                        print(f"      发布者: {app['publisher']}")
                    print(f"      路径: {app['exe_path']}")
            
            return unique_apps
            
        except Exception as e:
            print(f"❌ 获取应用程序列表时出错: {e}")
            import traceback
            traceback.print_exc()
            return []
    else:
        print("此功能仅在Windows系统上可用")
        return []

class SimpleWebSocketServer:
    def __init__(self, host='localhost', port=8765, pipe_path=None, pipe_port=None):
        self.host = host
        self.port = port
        self.clients = set()
        self.is_running = False
        self.server_socket = None
        self.server_thread = None
        
        # 应用程序枚举相关
        self.applications_broadcast_thread = None
        self.applications_broadcast_running = False
        
        # 音频相关（仅用于传输）
        self.audio_start_time = None
        self.frame_start_time = None
        self.frame_index = 0
        
        # WebSocket帧率控制
        self.websocket_target_fps = 120  # WebSocket目标帧率提高到120
        self.websocket_last_frame_time = 0
        self.websocket_frame_interval = 1.0 / self.websocket_target_fps
        
        # 性能统计
        self.websocket_frame_count = 0
        self.websocket_last_stats_time = time.time()
        self.websocket_skipped_frames = 0
        
        # 管道相关
        self.is_windows = platform.system() == "Windows"
        if self.is_windows:
            # Windows使用TCP socket作为管道替代
            self.pipe_port = pipe_port or 8766
            self.pipe_socket = None
        else:
            # Unix/Linux使用命名管道
            self.pipe_path = pipe_path or "/tmp/audio_pipe"
            self.pipe_fd = None
        
        self.pipe_thread = None
        self.pipe_enabled = False
        
        # 音频数据缓冲相关
        self.audio_buffer = bytearray()
        self.audio_buffer_lock = threading.Lock()
        self.expected_chunk_size = 4096  # 期望的音频块大小 (1024样本 * 2声道 * 2字节)
        
        # 设置日志
        self._setup_logging()
        
        # 启动服务器
        self.start_server()
    
    def _setup_logging(self):
        """设置日志配置"""
        logging.basicConfig(level=logging.INFO)
        logger = logging.getLogger(__name__)
    
    def start_server(self):
        """启动WebSocket服务器"""
        if self.is_running:
            logger.warning("WebSocket服务器已经在运行")
            return
            
        try:
            # 创建TCP服务器
            self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            self.server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
            self.server_socket.bind((self.host, self.port))
            self.server_socket.listen(5)
            
            self.is_running = True
            logger.info(f"WebSocket服务器已启动，监听 {self.host}:{self.port}")
            
            # 在后台线程中接受连接
            self.server_thread = threading.Thread(target=self._accept_connections, daemon=True)
            self.server_thread.start()
            
            # 启动管道监听
            self.start_pipe_listener()
            
            # 启动应用程序列表广播
            self.start_applications_broadcast()
            
        except Exception as e:
            logger.error(f"启动WebSocket服务器失败: {e}")
            self.is_running = False
            if self.server_socket:
                self.server_socket.close()
    
    def start_applications_broadcast(self):
        """启动应用程序列表广播"""
        if self.applications_broadcast_running:
            logger.warning("应用程序列表广播已经在运行")
            return
            
        self.applications_broadcast_running = True
        self.applications_broadcast_thread = threading.Thread(target=self._applications_broadcast_loop, daemon=True)
        self.applications_broadcast_thread.start()
        logger.info("应用程序列表广播已启动")
    
    def _applications_broadcast_loop(self):
        """应用程序列表广播循环"""
        while self.applications_broadcast_running and self.is_running:
            try:
                if self.clients:
                    # 获取应用程序列表
                    print('获取应用程序列表')
                    applications = get_all_applications()
                    print('applications',applications)
                    message = {
                        'type': 'applications_list',
                        'data': applications,
                        'timestamp': time.time()
                    }
                    
                    # 发送到所有连接的客户端
                    disconnected_clients = set()
                    for client in list(self.clients):
                        try:
                            self._send_text_message(client, message)
                        except Exception as e:
                            logger.error(f"发送应用程序列表到客户端失败: {e}")
                            disconnected_clients.add(client)
                    
                    # 清理断开的客户端
                    for client in disconnected_clients:
                        self.clients.discard(client)
                        try:
                            client.close()
                        except:
                            pass
                    
                    if self.clients:
                        logger.debug(f"已向 {len(self.clients)} 个客户端广播应用程序列表")
                
                # 等待5秒
                time.sleep(5)
                
            except Exception as e:
                logger.error(f"应用程序列表广播时出错: {e}")
                time.sleep(5)  # 出错时等待5秒再重试
    
    def stop_applications_broadcast(self):
        """停止应用程序列表广播"""
        if not self.applications_broadcast_running:
            return
            
        self.applications_broadcast_running = False
        logger.info("应用程序列表广播已停止")
        
        if self.applications_broadcast_thread and self.applications_broadcast_thread.is_alive():
            self.applications_broadcast_thread.join(timeout=2)
    
    def start_pipe_listener(self):
        """启动管道监听器"""
        if self.pipe_enabled:
            logger.warning("管道监听器已经在运行")
            return
            
        try:
            if self.is_windows:
                # Windows: 启动TCP socket监听器
                self._start_windows_pipe_listener()
            else:
                # Unix/Linux: 启动命名管道监听器
                self._start_unix_pipe_listener()
                
        except Exception as e:
            logger.error(f"启动管道监听器失败: {e}")
            self.pipe_enabled = False
    
    def _start_windows_pipe_listener(self):
        """启动Windows TCP socket管道监听器"""
        try:
            self.pipe_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            self.pipe_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
            self.pipe_socket.bind((self.host, self.pipe_port))
            self.pipe_socket.listen(1)
            self.pipe_socket.settimeout(1.0)  # 设置超时以便检查停止状态
            
            self.pipe_enabled = True
            
            # 启动管道监听线程
            self.pipe_thread = threading.Thread(target=self._windows_pipe_listener_loop, daemon=True)
            self.pipe_thread.start()
            logger.info(f"Windows管道监听器已启动，监听端口: {self.pipe_port}")
            
        except Exception as e:
            logger.error(f"启动Windows管道监听器失败: {e}")
            self.pipe_enabled = False
    
    def _start_unix_pipe_listener(self):
        """启动Unix命名管道监听器"""
        try:
            # 创建命名管道（如果不存在）
            if not os.path.exists(self.pipe_path):
                os.mkfifo(self.pipe_path)
                logger.info(f"创建命名管道: {self.pipe_path}")
            
            self.pipe_enabled = True
            
            # 启动管道监听线程
            self.pipe_thread = threading.Thread(target=self._unix_pipe_listener_loop, daemon=True)
            self.pipe_thread.start()
            logger.info("Unix管道监听器已启动")
            
        except Exception as e:
            logger.error(f"启动Unix管道监听器失败: {e}")
            self.pipe_enabled = False
    
    def stop_pipe_listener(self):
        """停止管道监听器"""
        if not self.pipe_enabled:
            return
            
        self.pipe_enabled = False
        logger.info("管道监听器已停止")
        
        if self.is_windows:
            # Windows: 关闭TCP socket
            if self.pipe_socket:
                try:
                    self.pipe_socket.close()
                    self.pipe_socket = None
                except:
                    pass
        else:
            # Unix: 关闭管道文件描述符
            if self.pipe_fd:
                try:
                    os.close(self.pipe_fd)
                    self.pipe_fd = None
                except:
                    pass
    
    def _windows_pipe_listener_loop(self):
        """Windows TCP socket管道监听循环"""
        try:
            logger.info("Windows管道监听线程已启动")
            
            while self.pipe_enabled and self.is_running:
                try:
                    # 接受音频数据发送进程的连接
                    try:
                        client_socket, address = self.pipe_socket.accept()
                        logger.info(f"音频数据发送进程已连接: {address}")
                        
                        # 处理音频数据
                        self._handle_windows_pipe_client(client_socket)
                        
                    except socket.timeout:
                        # 超时，继续检查是否需要停止
                        continue
                    except Exception as e:
                        if self.pipe_enabled:
                            logger.error(f"Windows管道接受连接时出错: {e}")
                        break
                        
                except Exception as e:
                    if self.pipe_enabled:
                        logger.error(f"Windows管道监听循环出错: {e}")
                    time.sleep(1)
                    
        except Exception as e:
            logger.error(f"Windows管道监听线程出错: {e}")
        finally:
            logger.info("Windows管道监听线程已停止")
    
    def _handle_windows_pipe_client(self, client_socket):
        """处理Windows管道客户端连接"""
        try:
            print("正在开始读取音频数据")
            client_socket.settimeout(1.0)
            
            # 初始化PCM文件保存（追加模式）
            pcm_file_path = "audio.pcm"
            pcm_file = None
            total_bytes_saved = 0
            start_time = time.time()
            
            try:
                # 检查文件是否存在，如果存在则获取当前大小
                file_exists = os.path.exists(pcm_file_path)
                if file_exists:
                    current_file_size = os.path.getsize(pcm_file_path)
                    print(f"PCM文件已存在: {pcm_file_path}")
                    print(f"当前文件大小: {current_file_size:,} 字节")
                    print(f"将以追加模式继续写入")
                else:
                    current_file_size = 0
                    print(f"PCM文件不存在，将创建新文件: {pcm_file_path}")
                
                # 以追加模式打开PCM文件
                pcm_file = open(pcm_file_path, 'ab')  # 'ab' = 追加二进制模式
                print(f"PCM文件已打开（追加模式）: {pcm_file_path}")
                
                while self.pipe_enabled and self.is_running:
                    try:
                        # 读取音频数据
                        audio_data = client_socket.recv(4096)
                        
                        if audio_data:
                            # 保存音频数据到PCM文件（追加模式）
                            if pcm_file:
                                pcm_file.write(audio_data)
                                pcm_file.flush()  # 确保数据立即写入磁盘
                                total_bytes_saved += len(audio_data)
                                
                                # 每1MB显示一次保存进度
                                if total_bytes_saved % (1024 * 1024) == 0:
                                    mb_saved = total_bytes_saved / (1024 * 1024)
                                    elapsed_time = time.time() - start_time
                                    total_file_size = current_file_size + total_bytes_saved
                                    total_mb = total_file_size / (1024 * 1024)
                                    print(f"本次会话已保存: {mb_saved:.1f} MB, 总文件大小: {total_mb:.1f} MB, 运行时间: {elapsed_time:.1f}秒")
                            
                            # 处理接收到的音频数据（原有功能）
                            self._handle_received_audio(audio_data)
                        else:
                            # 连接已关闭
                            break
                            
                    except socket.timeout:
                        # 超时，继续检查状态
                        continue
                    except Exception as e:
                        logger.error(f"Windows管道读取音频数据时出错: {e}")
                        break
                        
            finally:
                # 关闭PCM文件
                if pcm_file:
                    pcm_file.close()
                    pcm_file = None
                    
                    # 显示最终统计信息
                    elapsed_time = time.time() - start_time
                    mb_total = total_bytes_saved / (1024 * 1024)
                    final_file_size = current_file_size + total_bytes_saved
                    final_mb = final_file_size / (1024 * 1024)
                    
                    print(f"PCM文件追加保存完成!")
                    print(f"文件路径: {pcm_file_path}")
                    print(f"本次会话保存: {mb_total:.2f} MB")
                    print(f"文件总大小: {final_mb:.2f} MB")
                    print(f"运行时间: {elapsed_time:.1f}秒")
                    
                    # 计算音频时长 (48kHz, 16bit, 立体声)
                    sample_rate = 48000
                    channels = 2
                    bytes_per_sample = 2
                    total_audio_duration = final_file_size / (sample_rate * channels * bytes_per_sample)
                    session_audio_duration = total_bytes_saved / (sample_rate * channels * bytes_per_sample)
                    print(f"本次会话音频时长: {session_audio_duration:.2f}秒")
                    print(f"文件总音频时长: {total_audio_duration:.2f}秒")
                    
        except Exception as e:
            logger.error(f"处理Windows管道客户端时出错: {e}")
        finally:
            try:
                client_socket.close()
            except:
                pass
            logger.info("Windows管道客户端连接已关闭")
    
    def _unix_pipe_listener_loop(self):
        """Unix命名管道监听循环"""
        try:
            logger.info("Unix管道监听线程已启动")
            
            while self.pipe_enabled and self.is_running:
                try:
                    # 打开管道进行读取
                    with open(self.pipe_path, 'rb') as pipe:
                        self.pipe_fd = pipe.fileno()
                        
                        while self.pipe_enabled and self.is_running:
                            # 使用select进行非阻塞读取
                            ready, _, _ = select.select([pipe], [], [], 1.0)
                            
                            if ready:
                                # 读取音频数据
                                audio_data = pipe.read(4096)  # 读取4KB数据
                                if audio_data:
                                    # 处理接收到的音频数据
                                    self._handle_received_audio(audio_data)
                                else:
                                    # 没有数据，短暂等待
                                    time.sleep(0.01)
                            else:
                                # 超时，检查是否需要继续运行
                                continue
                                
                except Exception as e:
                    logger.error(f"Unix管道读取错误: {e}")
                    time.sleep(1)  # 出错时等待1秒再重试
                    
        except Exception as e:
            logger.error(f"Unix管道监听线程出错: {e}")
        finally:
            logger.info("Unix管道监听线程已停止")
    
    def _handle_received_audio(self, audio_data):
        """处理接收到的音频数据"""
        try:
            with self.audio_buffer_lock:
                # 将新接收的音频数据添加到缓冲区
                self.audio_buffer.extend(audio_data)
                logger.debug(f"接收到音频数据: {len(audio_data)} 字节，缓冲区大小: {len(self.audio_buffer)} 字节")
                
                # 处理缓冲区中的完整音频块
                while len(self.audio_buffer) >= self.expected_chunk_size:
                    # 提取一个完整的音频块
                    chunk_data = bytes(self.audio_buffer[:self.expected_chunk_size])
                    self.audio_buffer = self.audio_buffer[self.expected_chunk_size:]
                    
                    # 编码并发送完整的音频块
                    sync_timestamp = time.time()
                    audio_message = self._encode_audio_for_websocket(chunk_data, sync_timestamp)
                    
                    if audio_message:
                        # 广播音频数据
                        self.broadcast_audio(audio_message)
                        logger.debug(f"发送完整音频块: {len(chunk_data)} 字节，缓冲区剩余: {len(self.audio_buffer)} 字节")
                    else:
                        logger.error("编码音频块失败")
                
                # 如果缓冲区中还有不完整的数据，记录日志
                if self.audio_buffer:
                    logger.debug(f"缓冲区中剩余不完整数据: {len(self.audio_buffer)} 字节")
                    
        except Exception as e:
            logger.error(f"处理接收到的音频数据时出错: {e}")
    
    def _encode_audio_for_websocket(self, audio_data, sync_timestamp):
        """将音频数据编码为WebSocket可传输的格式"""
        try:
            # 将音频数据转换为base64编码
            audio_base64 = base64.b64encode(audio_data).decode('utf-8')
            
            # 创建音频消息
            audio_message = {
                'type': 'audio',
                'data': audio_base64,
                'format': 'pcm',
                'channels': 2,
                'rate': 48000,
                'chunk': 1024,
                'timestamp': datetime.now().isoformat(),
                'sync_timestamp': sync_timestamp,
                'size': len(audio_data)
            }
            
            return audio_message
            
        except Exception as e:
            logger.error(f"编码音频时出错: {e}")
            return None
    
    def broadcast_audio(self, audio_message):
        """向所有连接的客户端广播音频数据"""
        if not self.clients or not self.is_running:
            return
            
        try:
            # 向所有客户端发送音频
            disconnected_clients = set()
            
            for client in self.clients:
                try:
                    self._send_text_message(client, audio_message)
                except Exception as e:
                    logger.error(f"向客户端发送音频时出错: {e}")
                    disconnected_clients.add(client)
            
            # 移除断开的客户端
            for client in disconnected_clients:
                self.clients.remove(client)
                try:
                    client.close()
                except:
                    pass
            
            if self.clients:
                logger.debug(f"向 {len(self.clients)} 个客户端广播音频")
                
        except Exception as e:
            logger.error(f"广播音频时出错: {e}")
    
    def _accept_connections(self):
        """接受客户端连接"""
        while self.is_running:
            try:
                client_socket, address = self.server_socket.accept()
                logger.info(f"新客户端连接: {address}")
                
                # 为每个客户端创建处理线程
                client_thread = threading.Thread(
                    target=self._handle_client, 
                    args=(client_socket, address),
                    daemon=True
                )
                client_thread.start()
                
            except Exception as e:
                if self.is_running:
                    logger.error(f"接受连接时出错: {e}")
                break
    
    def _handle_client(self, client_socket, address):
        """处理客户端连接"""
        try:
            # 执行WebSocket握手
            if not self._perform_handshake(client_socket):
                logger.warning(f"客户端 {address} 握手失败")
                client_socket.close()
                return
            
            # 添加到客户端列表
            self.clients.add(client_socket)
            logger.info(f"客户端 {address} 握手成功，当前连接数: {len(self.clients)}")
            
            # 发送连接确认消息
            self._send_text_message(client_socket, {
                'type': 'connection',
                'message': '连接成功',
                'timestamp': datetime.now().isoformat()
            })
            
            # 保持连接并处理消息
            while self.is_running:
                try:
                    # 接收WebSocket帧
                    frame = self._receive_frame(client_socket)
                    if frame is None:
                        break
                    
                    # 处理消息
                    if frame['opcode'] == 0x8:  # 关闭帧
                        break
                    elif frame['opcode'] == 0x9:  # Ping帧
                        self._send_pong(client_socket)
                    elif frame['opcode'] == 0x1:  # 文本帧
                        try:
                            data = json.loads(frame['payload'].decode('utf-8'))
                            self._handle_client_message(client_socket, data)
                        except json.JSONDecodeError:
                            logger.warning(f"收到无效JSON消息: {frame['payload']}")
                            
                except Exception as e:
                    logger.error(f"处理客户端消息时出错: {e}")
                    break
                    
        except Exception as e:
            logger.error(f"处理客户端 {address} 时出错: {e}")
        finally:
            # 清理客户端
            if client_socket in self.clients:
                self.clients.remove(client_socket)
            client_socket.close()
            logger.info(f"客户端 {address} 断开连接，当前连接数: {len(self.clients)}")
    
    def _handle_client_message(self, client_socket, data):
        """处理客户端消息"""
        message_type = data.get('type')
        
        if message_type == 'ping':
            # 心跳检测
            self._send_text_message(client_socket, {
                'type': 'pong',
                'timestamp': datetime.now().isoformat()
            })
        elif message_type == 'request_frame':
            # 客户端请求新帧
            self._send_text_message(client_socket, {
                'type': 'frame_requested',
                'message': '帧请求已收到',
                'timestamp': datetime.now().isoformat()
            })
        elif message_type == 'start_audio':
            # 启动音频捕获
            self._send_text_message(client_socket, {
                'type': 'audio_started',
                'message': '音频捕获已启动',
                'timestamp': datetime.now().isoformat()
            })
        elif message_type == 'stop_audio':
            # 停止音频捕获
            self._send_text_message(client_socket, {
                'type': 'audio_stopped',
                'message': '音频捕获已停止',
                'timestamp': datetime.now().isoformat()
            })
        elif message_type == 'request_audio':
            # 请求音频状态
            self._send_text_message(client_socket, {
                'type': 'audio_started',
                'message': '音频捕获正在运行',
                'timestamp': datetime.now().isoformat()
            })
        elif message_type == 'launch_app':
            # 处理启动应用程序请求
            exe_path = data.get('exe_path')
            if exe_path and os.path.exists(exe_path):
                try:
                    subprocess.Popen([exe_path])
                    response = {
                        'type': 'launch_result',
                        'success': True,
                        'message': f'应用程序启动成功: {exe_path}'
                    }
                except Exception as e:
                    response = {
                        'type': 'launch_result',
                        'success': False,
                        'message': f'启动失败: {str(e)}'
                    }
            else:
                response = {
                    'type': 'launch_result',
                    'success': False,
                    'message': '应用程序路径不存在'
                }
            
            self._send_text_message(client_socket, response)
        else:
            logger.info(f"收到未知消息类型: {message_type}")
    
    def _perform_handshake(self, client_socket):
        """执行WebSocket握手"""
        try:
            # 接收HTTP请求
            request = client_socket.recv(1024).decode('utf-8')
            if not request.startswith('GET'):
                return False
            
            # 提取Sec-WebSocket-Key
            lines = request.split('\n')
            key = None
            for line in lines:
                if line.startswith('Sec-WebSocket-Key:'):
                    key = line.split(':')[1].strip()
                    break
            
            if not key:
                return False
            
            # 生成Sec-WebSocket-Accept
            import hashlib
            import base64
            magic_string = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
            accept_key = base64.b64encode(
                hashlib.sha1((key + magic_string).encode()).digest()
            ).decode()
            
            # 发送握手响应
            response = (
                "HTTP/1.1 101 Switching Protocols\r\n"
                "Upgrade: websocket\r\n"
                "Connection: Upgrade\r\n"
                f"Sec-WebSocket-Accept: {accept_key}\r\n"
                "\r\n"
            )
            client_socket.send(response.encode())
            return True
            
        except Exception as e:
            logger.error(f"握手失败: {e}")
            return False
    
    def _receive_frame(self, client_socket):
        """接收WebSocket帧"""
        try:
            # 读取帧头（至少2字节）
            header = client_socket.recv(2)
            if len(header) < 2:
                return None
            
            # 解析帧头
            first_byte = header[0]
            second_byte = header[1]
            
            fin = (first_byte & 0x80) != 0
            opcode = first_byte & 0x0F
            masked = (second_byte & 0x80) != 0
            payload_length = second_byte & 0x7F
            
            # 处理扩展长度
            if payload_length == 126:
                length_bytes = client_socket.recv(2)
                payload_length = struct.unpack('>H', length_bytes)[0]
            elif payload_length == 127:
                length_bytes = client_socket.recv(8)
                payload_length = struct.unpack('>Q', length_bytes)[0]
            
            # 读取掩码（如果存在）
            mask = None
            if masked:
                mask = client_socket.recv(4)
            
            # 读取负载
            payload = b''
            if payload_length > 0:
                payload = client_socket.recv(payload_length)
                
                # 应用掩码
                if masked and mask:
                    payload = bytes(payload[i] ^ mask[i % 4] for i in range(len(payload)))
            
            return {
                'fin': fin,
                'opcode': opcode,
                'masked': masked,
                'payload_length': payload_length,
                'payload': payload
            }
            
        except Exception as e:
            logger.error(f"接收帧时出错: {e}")
            return None
    
    def _send_frame(self, client_socket, opcode, payload):
        """发送WebSocket帧"""
        try:
            # 构建帧头
            frame = bytearray()
            
            # 第一个字节：FIN + RSV + Opcode
            frame.append(0x80 | opcode)  # FIN=1, RSV=000, Opcode
            
            # 第二个字节：MASK + Payload Length
            payload_length = len(payload)
            if payload_length < 126:
                frame.append(payload_length)
            elif payload_length < 65536:
                frame.append(126)
                frame.extend(struct.pack('>H', payload_length))
            else:
                frame.append(127)
                frame.extend(struct.pack('>Q', payload_length))
            
            # 添加负载
            frame.extend(payload)
            
            client_socket.send(frame)
            
        except Exception as e:
            logger.error(f"发送帧时出错: {e}")
    
    def _send_text_message(self, client_socket, data):
        """发送文本消息"""
        try:
            message = json.dumps(data)
            self._send_frame(client_socket, 0x1, message.encode('utf-8'))
        except Exception as e:
            logger.error(f"发送文本消息时出错: {e}")
    
    def _send_pong(self, client_socket):
        """发送Pong响应"""
        try:
            self._send_frame(client_socket, 0xA, b'')
        except Exception as e:
            logger.error(f"发送Pong时出错: {e}")
    
    def broadcast_frame(self, image, sync_timestamp=None, frame_index=None):
        """向所有连接的客户端广播帧数据"""
        if not self.clients or not self.is_running:
            return
        
        # 移除帧率限制，尽可能快地传输
        current_time = time.time()
        self.websocket_frame_count += 1
        
        # 每5秒输出一次性能统计
        if current_time - self.websocket_last_stats_time >= 5:
            actual_fps = self.websocket_frame_count / (current_time - self.websocket_last_stats_time)
            logger.info(f"WebSocket性能: 实际帧率={actual_fps:.1f}FPS, 跳过帧数={self.websocket_skipped_frames}")
            self.websocket_frame_count = 0
            self.websocket_skipped_frames = 0
            self.websocket_last_stats_time = current_time
            
        try:
            # 编码图像
            frame_data = self.encode_frame_for_websocket(image, sync_timestamp, frame_index)
            if not frame_data:
                return
            
            # 向所有客户端发送帧
            disconnected_clients = set()
            
            for client in self.clients:
                try:
                    self._send_text_message(client, frame_data)
                except Exception as e:
                    logger.error(f"向客户端发送帧时出错: {e}")
                    disconnected_clients.add(client)
            
            # 移除断开的客户端
            for client in disconnected_clients:
                self.clients.remove(client)
                try:
                    client.close()
                except:
                    pass
            
            if self.clients:
                logger.debug(f"向 {len(self.clients)} 个客户端广播帧")
                
        except Exception as e:
            logger.error(f"广播帧时出错: {e}")
    
    def encode_frame_for_websocket(self, image, sync_timestamp=None, frame_index=None):
        """将PIL图像编码为WebSocket可传输的格式"""
        try:
            # 保持原始分辨率，只优化编码质量
            if hasattr(image, 'size'):
                width, height = image.size
            else:
                width, height = 0, 0
            
            # 将PIL图像转换为JPEG格式的字节流
            img_byte_arr = io.BytesIO()
            
            # 根据图像大小动态调整质量，保持分辨率不变
            if width >= 1920 and height >= 1080:
                quality = 50  # 4K图像使用较低质量以提高速度
            elif width >= 1280 and height >= 720:
                quality = 55  # 1080p图像
            elif width >= 800 and height >= 600:
                quality = 60  # 中等分辨率
            else:
                quality = 65  # 小图像使用较高质量
            
            # 使用最快的编码设置
            image.save(img_byte_arr, format='JPEG', quality=quality, optimize=False, progressive=False)
            img_byte_arr = img_byte_arr.getvalue()
            
            # 转换为base64编码
            img_base64 = base64.b64encode(img_byte_arr).decode('utf-8')
            
            # 使用同步时间戳或当前时间
            if sync_timestamp is None:
                sync_timestamp = time.time()
            
            if frame_index is None:
                frame_index = self.frame_index
                self.frame_index += 1
            
            # 创建帧数据消息
            frame_message = {
                'type': 'frame',
                'data': img_base64,
                'format': 'jpeg',
                'timestamp': datetime.now().isoformat(),
                'sync_timestamp': sync_timestamp,  # 同步时间戳
                'frame_index': frame_index,  # 帧索引
                'size': len(img_byte_arr)
            }
            
            return frame_message
            
        except Exception as e:
            logger.error(f"编码帧时出错: {e}")
            return None
    
    def stop_server(self):
        """停止WebSocket服务器"""
        if not self.is_running:
            return
            
        logger.info("正在停止WebSocket服务器...")
        self.is_running = False
        
        # 停止应用程序列表广播
        self.stop_applications_broadcast()
        
        # 停止管道监听
        self.pipe_enabled = False
        
        # 清理音频缓冲区
        with self.audio_buffer_lock:
            remaining_data = len(self.audio_buffer)
            if remaining_data > 0:
                logger.info(f"清理音频缓冲区，剩余数据: {remaining_data} 字节")
                self.audio_buffer.clear()
        
        # 关闭所有客户端连接
        for client in list(self.clients):
            try:
                client.close()
            except:
                pass
        self.clients.clear()
        
        # 关闭服务器socket
        if self.server_socket:
            try:
                self.server_socket.close()
            except:
                pass
            self.server_socket = None
        
        # 停止管道线程
        if self.pipe_thread and self.pipe_thread.is_alive():
            self.pipe_thread.join(timeout=2)
        
        logger.info("WebSocket服务器已停止")
    
    def get_audio_buffer_status(self):
        """获取音频缓冲区状态"""
        with self.audio_buffer_lock:
            return {
                'buffer_size': len(self.audio_buffer),
                'expected_chunk_size': self.expected_chunk_size,
                'complete_chunks_available': len(self.audio_buffer) // self.expected_chunk_size,
                'remaining_bytes': len(self.audio_buffer) % self.expected_chunk_size
            }
    
    def get_client_count(self):
        """获取当前连接的客户端数量"""
        return len(self.clients)
    
    def set_websocket_fps(self, fps):
        """设置WebSocket目标帧率"""
        self.websocket_target_fps = max(1, fps)
        self.websocket_frame_interval = 1.0 / self.websocket_target_fps
        logger.info(f"WebSocket帧率设置为: {self.websocket_target_fps} FPS")
    
    def is_server_running(self):
        """检查服务器是否正在运行"""
        return self.is_running

# 全局服务器实例
websocket_server = None

def get_websocket_server():
    """获取全局WebSocket服务器实例（SimpleWebSocketServer）"""
    global websocket_server
    if websocket_server is None:
        websocket_server = SimpleWebSocketServer()
    return websocket_server